package poker;
import java.util.ArrayList;

class Hand 
{
	private String s;
	private int[] value;
	private ArrayList<Card> hand;
	Hand() 
	{
		hand = new ArrayList<Card>(5);
	}
   
	int findRankIndex(final int rank) 
	{
		int result = 0;
		for (int i = 0; i < 5; i++) 
		{
			if (hand.get(i).getRank() == rank) 
			{
				result = i;
			}
		}
		return result;
	}
   
	Card getCard(int i) throws PokerException
	{
		if (i >= hand.size()) 
		{
			throw new PokerException("No such index");
		} 
		else 
		{
			return hand.get(i);
		}
	}
   
	void cardRemove(final int i) 
	{
			hand.remove(i);
	}
	void cardPick(final Deck deck) 
	{
		hand.add(deck.drawFromDeck());
	}
   
	int[] getRanks() 
	{
		int[] result = new int[13];
		for (int i = 0; i < 5; i++) 
		{
		result[hand.get(i).getRank()]++;
		}
		return result;
	}
	private int getSize() 
	{
		if (hand == null) 
		{
			return 0;
		} 
		else 
		{
			return hand.size();
		}
	}
	//metoda wyznaczania wartosci ukladu reki
	void evaluate()
	{
		//tablica przechowujaca info o liczebnosci figur kart w rece
		//np. ranks={0,0,0,2,1,0,1,0,0,0,0,0,1,0} oznacza, ze w rece sa dwie piatki, jedna szostka, jedna osemka i jeden krol
        int[] ranks = new int[14];
		//grupy tych samych kart
        int group1=1, group2=1;
		//rangi grup tych samych kart
        int group1Rank=0, group2Rank=0;		
		//uporzadkowana malejaco tablica figur kart dodatkowych, spoza ukladu
        int[] highestCards = new int[5]; 
		//index tabeli highestCards
        int index=0;		
		boolean flush=true, straight=false;		
		//ranga najwyzszej karty w stricie
        int topStraightCard=0;		
		//wartosci ukladu reki
		value = new int[6];
		//pobieranie kart z talii
        			
        for (int x=0; x<=13; x++)
        {
            ranks[x]=0;
        }
		//zapisywanie liczebnosci kart o danej figurze
        for (int x=0; x<=4; x++)
        {
            ranks[hand.get(x).getRank()]++;
        }
		//laczenie tych samych kart w grupy
        for (int x=12; x>=0; x--)
        {
			if (ranks[x] > group1)
			{
				if (group1 != 1)               
				{
					group2 = group1;
					group2Rank = group1Rank;
				}
				group1 = ranks[x];
				group1Rank = x;
			}
			else if (ranks[x] > group2)
			{
				group2 = ranks[x];
				group2Rank = x;
			}
        }
		//uzupelnianie tablicy figur kart dodatkowych w kolejnosci malejacej
        for (int x=12; x>=0; x--)
        {
            if (ranks[x]==1)
            {
                highestCards[index]=x;
                index++;
            }
        }
		//sprawdzanie czy kolor
        for (int x=0; x<4; x++) 
		{
            if (hand.get(x).getSuit()!=hand.get(x+1).getSuit())
			flush=false;
        }
        //sprawdzanie czy strit
		//najmniejsza karta w ace high stricie to 10
        for (int x=0; x<=8; x++)
        {
            if (ranks[x]==1 && ranks[x+1]==1 && ranks[x+2]==1 && 
                ranks[x+3]==1 && ranks[x+4]==1)
            {
                topStraightCard=x+4;
				straight=true;
                break;
            }
        }
        for (int x=0; x<=5; x++)
        {
            value[x]=0;
        }
        //wyznaczanie wartosci ukladu kart
		//wyznaczane sa wartosci glownego ukladu oraz kart dodatkowych
		
		//high card
        if ( group1==1 ) 
		{
            value[0]=1;
            value[1]=highestCards[0];
            value[2]=highestCards[1];
            value[3]=highestCards[2];
            value[4]=highestCards[3];
            value[5]=highestCards[4];
        }
		//pair
        if (group1==2 && group2==1)
        {
            value[0]=2;
            value[1]=group1Rank;
            value[2]=highestCards[0];
            value[3]=highestCards[1];
            value[4]=highestCards[2];
        }
		//two pair
        if (group1==2 && group2==2)
        {
            value[0]=3;
			value[1]=group1Rank;
			value[2]=group2Rank;
            value[3]=highestCards[0];
        }
		//three of a kind
        if (group1==3 && group2!=2)
        {
            value[0]=4;
            value[1]=group1Rank;
            value[2]=highestCards[0];
            value[3]=highestCards[1];
        }
		//straight
        if (straight && !flush)
        {
            value[0]=5;
            value[1]=topStraightCard;
        }
		//flush
        if (flush && !straight)
        {
            value[0]=6;
            value[1]=highestCards[0];
            value[2]=highestCards[1];
            value[3]=highestCards[2];
            value[4]=highestCards[3];
            value[5]=highestCards[4];
        }
		//full house
        if (group1==3 && group2==2)
        {
            value[0]=7;
            value[1]=group1Rank;
            value[2]=group2Rank;
        }
		//four of a kind
        if (group1==4)
        {
            value[0]=8;
            value[1]=group1Rank;
            value[2]=highestCards[0];
        }
		//poker
        if (straight && flush)
        {
            value[0]=9;
            value[1]=topStraightCard;
        }
    }
		
	int getHandRank() throws PokerException
	{
		if (getSize() != 5)
		throw new PokerException("This is not a full hand!");
		evaluate();
		return value[0];
	}
	//wyswietlanie posiadanego ukladu kart
    void display()
    {
		evaluate();
        s = new String();
        switch( value[0] )
        {
            case 1:
				s="high card";
                break;
            case 2:
                s="pair of " + Card.rankAsString(value[1]) + "\'s";
                break;
            case 3:
                s="two pair " + Card.rankAsString(value[1]) + " " + Card.rankAsString(value[2]);
                break;
            case 4:
                s="three of a kind " + Card.rankAsString(value[1]) + "\'s";
                break;
            case 5:
                s=Card.rankAsString(value[1]) + " high straight";
                break;
            case 6:
                s="flush";
                break;
            case 7:
                s="full house " + Card.rankAsString(value[1]) + " over " + Card.rankAsString(value[2]);
                break;
            case 8:
                s="four of a kind " + Card.rankAsString(value[1]);
                break;
            case 9:
                s="straight flush " + Card.rankAsString(value[1]) + " high";
                break;
            default:
                s="Error: cannot display hand";
        }
        System.out.println(s);
    }
	//porownywanie ukladow 1 - wiekszy; -1 - mniejszy, 0 - rowny
    int compareTo(Hand comp)
    {
        for (int x=0; x<6; x++)
        {
            if (this.value[x]>comp.value[x])
                return 1;
            else if (this.value[x]<comp.value[x])
                return -1;
        }
        return 0;
    }
    public String toString() 
	{
		String result = "";
		for (int i = 0; i < hand.size(); i++) 
		{
			result += hand.get(i).toString();
			result += "\n";
		}
		return result;
	}
}